home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xbomb-2.0 / xbomb-2 / xbomb / xwindow.c < prev   
C/C++ Source or Header  |  1995-11-15  |  24KB  |  827 lines

  1. /***************************************
  2.   $Header: /home/amb/xbomb/RCS/xwindow.c 1.14 1995/11/15 19:26:42 amb Exp $
  3.  
  4.   XBomb - 'Minesweeper' game - Version 2
  5.  
  6.   All X Window functions.
  7.  
  8.   Written by Andrew M. Bishop
  9.  
  10.   This file Copyright 1994 1995 Andrew M. Bishop
  11.   It may be distributed under the GNU Public License, version 2, or
  12.   any higher version.  See section COPYING of the GNU Public license
  13.   for conditions under which this file may be redistributed.
  14.   ***************************************/
  15.  
  16.  
  17. #include <X11/X.h>
  18. #include <X11/Xlib.h>
  19. #include <X11/Intrinsic.h>
  20. #include <X11/StringDefs.h>
  21. #include <X11/Xaw/Command.h>
  22. #include <X11/Xaw/Form.h>
  23. #include <X11/Xaw/Label.h>
  24. #include <X11/Xaw/MenuButton.h>
  25. #include <X11/Xaw/SimpleMenu.h>
  26. #include <X11/Xaw/SmeBSB.h>
  27. #include <X11/keysym.h>
  28. #include <stdio.h>
  29. #include <sys/time.h>
  30. #include <unistd.h>
  31.  
  32. #include "xbomb.h"
  33. #include "icon.h"
  34.  
  35. #if defined(__sun__)
  36. int gettimeofday(struct timeval *tv, struct timezone *tz);
  37. #endif
  38.  
  39. extern int grid_width,grid_height,grid_bombs,grid_type;
  40.  
  41. extern char levels[NLEVELS][LEVELSLEN],types[NTYPES][TYPESLEN];
  42.  
  43. static int xoffset,yoffset;
  44. static int status=0;
  45. static int unsigned scalex=10,scaley=10;
  46. static int unsigned pixw,pixh;
  47. static XtAppContext app_context;
  48. static Display* display;
  49. static Window play_window;
  50. static Widget play_area,clock_w,uxb_w;
  51. static Pixmap icon_p,bombpix[2]={0,0};
  52. static XPoint outline[8];
  53.  
  54. static void size_expose_proc(Widget w,XtPointer va,XEvent* e,Boolean* vb);
  55. static void mouse_press_proc(Widget w,XtPointer va,XEvent* e,Boolean* vb);
  56. static void key_press_proc(Widget w,XtPointer va,XEvent* e,Boolean* vb);
  57. static void change_status_proc(Widget widget,XtPointer clientData,XtPointer callData);
  58. static void hiscore_proc(Widget widget,XtPointer clientData,XtPointer callData);
  59. static void display_clock(XtPointer p,XtIntervalId i);
  60. static int msecs(void);
  61.  
  62. /*+ An array to hold the colour and font resource data in. +*/
  63. struct temp
  64. {
  65.  Pixel colours[6];
  66.  XFontStruct* fontstruct;
  67. }
  68. resources;
  69.  
  70. /*+ An array to hold the GCs in. +*/
  71. static GC gc[7];
  72.  
  73. #define GC_BOMB        0
  74. #define GC_ACTUAL_BACK 1
  75. #define GC_THINK_BACK  2
  76. #define GC_NUMBERS     3
  77. #define GC_UNSEEN      4
  78. #define GC_CORRECT     5
  79. #define GC_BLANK       6
  80.  
  81. /*+ The colour resources for the map. +*/
  82. static XtResource xresources[]=
  83. {
  84.  {"bomb"     , "XBomb"  , XtRPixel  , sizeof(String)  , 0                , XtRString, "black" },
  85.  {"bombreal" , "XBomb"  , XtRPixel  , sizeof(String)  ,   sizeof(String) , XtRString, "red" },
  86.  {"bombmark" , "XBomb"  , XtRPixel  , sizeof(String)  , 2*sizeof(String) , XtRString, "orange" },
  87.  {"number"   , "XBomb"  , XtRPixel  , sizeof(String)  , 3*sizeof(String) , XtRString, "blue" },
  88.  {"hidden"   , "XBomb"  , XtRPixel  , sizeof(String)  , 4*sizeof(String) , XtRString, "grey50" },
  89.  {"correct"  , "XBomb"  , XtRPixel  , sizeof(String)  , 5*sizeof(String) , XtRString, "green" },
  90.  {"font"     , "XBomb"  , XtRFontStruct , sizeof(XFontStruct*) , 6*sizeof(String), XtRString, "lucidasans-24"}
  91. };
  92.  
  93. /*++++++++++++++++++++++++++++++++++++++
  94.   Open the X connection.
  95.  
  96.   int *argc A pointer to the command line parameters.
  97.  
  98.   char **argv The pointer to the command line parameters.
  99.   ++++++++++++++++++++++++++++++++++++++*/
  100.  
  101. void InitialiseX(int *argc,char **argv)
  102. {
  103.  XFontStruct *fontstruct;
  104.  XGCValues values;
  105.  Widget toplevel,form,quit,start,menu,menushell,hiscore;
  106.  int i;
  107.  
  108.  /* Initialise the display */
  109.  
  110.  toplevel=XtVaAppInitialize(&app_context,"XBomb",
  111.                             NULL, (Cardinal)0,argc,argv,NULL,
  112.                             XtNtitle,"XBomb V2    [(c) AMB Software 1994,95]",
  113.                             XtNiconName,"XBomb",
  114.                             NULL);
  115.  
  116.  display=XtDisplay(toplevel);
  117.  
  118.  /* Create the widgets */
  119.  
  120.  form=XtVaCreateManagedWidget("form",formWidgetClass,toplevel,XtNwidth,100,XtNheight,100,NULL);
  121.  
  122.  start=XtVaCreateManagedWidget("start",commandWidgetClass,form,
  123.                                XtNlabel,"Start",
  124.                                XtNfromHoriz,NULL,XtNfromVert,NULL,
  125.                                XtNleft,XtChainLeft,XtNtop,XtChainTop,XtNright,XtChainLeft,XtNbottom,XtChainTop,
  126.                                NULL);
  127.  XtAddCallback(start,XtNcallback,change_status_proc,(XtPointer)GAME_START);
  128.  
  129.  menu=XtVaCreateManagedWidget("menu",menuButtonWidgetClass,form,
  130.                               XtNlabel,"Level",
  131.                               XtNmenuName,"levelmenushell",
  132.                               XtNfromHoriz,start,XtNfromVert,NULL,
  133.                               XtNleft,XtChainLeft,XtNtop,XtChainTop,XtNright,XtChainLeft,XtNbottom,XtChainTop,
  134.                               NULL);
  135.  
  136.  menushell=XtCreatePopupShell("levelmenushell",simpleMenuWidgetClass,menu,NULL,0);
  137.  
  138.  for(i=0;i<NLEVELS;i++)
  139.    {
  140.     Widget item=XtVaCreateManagedWidget(levels[i],smeBSBObjectClass,menushell,
  141.                                         XtNlabel,levels[i],
  142.                                         NULL);
  143.     XtAddCallback(item,XtNcallback,change_status_proc,(XtPointer)(GAME_LEVEL+i));
  144.    }
  145.  
  146.  menu=XtVaCreateManagedWidget("menu",menuButtonWidgetClass,form,
  147.                               XtNlabel,"Game Type",
  148.                               XtNmenuName,"typemenushell",
  149.                               XtNfromHoriz,menu,XtNfromVert,NULL,
  150.                               XtNleft,XtChainLeft,XtNtop,XtChainTop,XtNright,XtChainLeft,XtNbottom,XtChainTop,
  151.                               NULL);
  152.  
  153.  menushell=XtCreatePopupShell("typemenushell",simpleMenuWidgetClass,menu,NULL,0);
  154.  
  155.  for(i=0;i<NTYPES;i++)
  156.    {
  157.     Widget item=XtVaCreateManagedWidget(types[i],smeBSBObjectClass,menushell,
  158.                                         XtNlabel,types[i],
  159.                                         NULL);
  160.     XtAddCallback(item,XtNcallback,change_status_proc,(XtPointer)(GAME_TYPE+i));
  161.    }
  162.  
  163.  hiscore=XtVaCreateManagedWidget("hiscore",commandWidgetClass,form,
  164.                                  XtNlabel,"Hi-Scores",
  165.                                  XtNfromHoriz,menu,XtNfromVert,NULL,
  166.                                  XtNleft,XtChainLeft,XtNtop,XtChainTop,XtNright,XtChainLeft,XtNbottom,XtChainTop,
  167.                                  NULL);
  168.  XtAddCallback(hiscore,XtNcallback,hiscore_proc,NULL);
  169.  
  170.  quit=XtVaCreateManagedWidget("quit",commandWidgetClass,form,
  171.                               XtNlabel,"Quit",
  172.                               XtNfromHoriz,hiscore,XtNfromVert,NULL,
  173.                               XtNleft,XtChainLeft,XtNtop,XtChainTop,XtNright,XtChainLeft,XtNbottom,XtChainTop,
  174.                               NULL);
  175.  XtAddCallback(quit,XtNcallback,change_status_proc,(XtPointer)GAME_QUIT);
  176.  
  177.  play_area=XtVaCreateManagedWidget("grid",coreWidgetClass,form,
  178.                                    XtNwidth,400,XtNheight,400,
  179.                                    XtNtop,XtChainTop,XtNright,XtChainRight,XtNleft,XtChainLeft,XtNbottom,XtChainBottom,
  180.                                    XtNfromHoriz,NULL,XtNfromVert,start,
  181.                                    XtNresizable,True,
  182.                                    NULL);
  183.  
  184.  XtAddEventHandler(play_area,ButtonPressMask,False,(XtEventHandler)mouse_press_proc,NULL);
  185.  XtAddEventHandler(play_area,KeyReleaseMask,False,(XtEventHandler)key_press_proc,NULL);
  186.  XtAddEventHandler(play_area,ExposureMask|StructureNotifyMask,False,(XtEventHandler)size_expose_proc,NULL);
  187.  
  188.  clock_w=XtVaCreateManagedWidget("clock",labelWidgetClass,form,
  189.                                  XtNlabel,"Time : MMMM.MMM",
  190.                                  XtNfromHoriz,NULL,XtNfromVert,play_area,
  191.                                  XtNtop,XtChainBottom,XtNright,XtChainLeft,XtNleft,XtChainLeft,XtNbottom,XtChainBottom,
  192.                                  NULL);
  193.  
  194.  uxb_w=XtVaCreateManagedWidget("uxb",labelWidgetClass,form,
  195.                                XtNlabel,"UXB : MMM",
  196.                                XtNfromHoriz,clock_w,XtNfromVert,play_area,
  197.                                XtNtop,XtChainBottom,XtNright,XtChainLeft,XtNleft,XtChainLeft,XtNbottom,XtChainBottom,
  198.                                NULL);
  199.  
  200.  /* Create graphics contexts */
  201.  
  202.  XtVaGetSubresources(play_area,(XtPointer)&resources,"grid","XBomb",xresources,XtNumber(xresources),NULL);
  203.  
  204.  values.font=resources.fontstruct->fid;
  205.  for(i=0;i<6;i++)
  206.    {
  207.     values.foreground=resources.colours[i];
  208.     if(i==4)
  209.       {
  210.        GC tempgc;
  211.        XGCValues gcxval;
  212.        Dimension w,h;
  213.        Pixmap stipple=XCreatePixmap(display,RootWindowOfScreen(XtScreen(toplevel)),8,8,1);
  214.  
  215.        gcxval.foreground=0;
  216.        gcxval.background=0;
  217.        tempgc=XCreateGC(display,stipple,GCForeground|GCBackground,&gcxval);
  218.  
  219.        XFillRectangle(display,stipple,tempgc,0,0,8,8);
  220.  
  221.        XSetForeground(display,tempgc,(unsigned long)~0);
  222.  
  223.        for(w=0;w<8;w++)
  224.           for(h=0;h<8;h++)
  225.              if((w+h)%2)
  226.                 XDrawPoint(display,stipple,tempgc,w,h);
  227.  
  228.        XtVaGetValues(play_area,XtNbackground,&values.background,NULL);
  229.        values.stipple=stipple;
  230.        values.fill_style=FillOpaqueStippled;
  231.        gc[i]=XCreateGC(display,RootWindowOfScreen(XtScreen(toplevel)),GCForeground|GCBackground|GCFont|GCStipple|GCFillStyle,&values);
  232.  
  233.        XFreeGC(display,tempgc);
  234.        XFreePixmap(display,stipple);
  235.       }
  236.     else
  237.        gc[i]=XCreateGC(display,RootWindowOfScreen(XtScreen(toplevel)),GCForeground|GCFont,&values);
  238.    }
  239.  
  240.  XtVaGetValues(play_area,XtNbackground,&values.foreground,NULL);
  241.  gc[GC_BLANK]=XCreateGC(display,RootWindowOfScreen(XtScreen(toplevel)),GCForeground,&values);
  242.  
  243.  /* Add the icon */
  244.  
  245.  icon_p=XCreateBitmapFromData(display,RootWindowOfScreen(XtScreen(toplevel)),
  246.                               icon_bits,icon_width,icon_height);
  247.  
  248.  XtVaSetValues(toplevel,XtNiconPixmap,icon_p,NULL);
  249.  
  250.  /* Show the widgets */
  251.  
  252.  XtRealizeWidget(toplevel);
  253.  XFlush(display);
  254.  
  255.  play_window=XtWindow(play_area);
  256.  
  257.  /* Centre the text */
  258.  
  259.  fontstruct=XQueryFont(display,XGContextFromGC(gc[GC_NUMBERS]));
  260.  
  261.  xoffset=XTextWidth(fontstruct,"0",1)/2;
  262.  yoffset=fontstruct->ascent/2;
  263. }
  264.  
  265.  
  266. /*++++++++++++++++++++++++++++++++++++++
  267.   Close the X connection.
  268.   ++++++++++++++++++++++++++++++++++++++*/
  269.  
  270. void FinishUpX(void)
  271. {
  272.  int i;
  273.  
  274.  for(i=0;i<7;i++)
  275.     XFreeGC(display,gc[i]);
  276.  
  277.  for(i=0;i<2;i++)
  278.     XFreePixmap(display,bombpix[i]);
  279.  
  280.  XFreePixmap(display,icon_p);
  281.  
  282.  XCloseDisplay(display);
  283. }
  284.  
  285.  
  286. /*++++++++++++++++++++++++++++++++++++++
  287.   Process events.
  288.  
  289.   int ProcessXEvents Returns the game status.
  290.   ++++++++++++++++++++++++++++++++++++++*/
  291.  
  292. int ProcessXEvents(void)
  293. {
  294.  XEvent event;
  295.  
  296.  status=0;
  297.  
  298.  XtAppNextEvent(app_context,&event);
  299.  XtDispatchEvent(&event);
  300.  
  301.  return(status);
  302. }
  303.  
  304.  
  305. /*++++++++++++++++++++++++++++++++++++++
  306.   Draw a value in the specified square.
  307.  
  308.   int x The X position.
  309.  
  310.   int y The y position.
  311.  
  312.   unsigned char value The value of the square.
  313.   ++++++++++++++++++++++++++++++++++++++*/
  314.  
  315. void DrawSquare(int x,int y,unsigned char value)
  316. {
  317.  int xpos=0,ypos=0;
  318.  static char grid_numbers[13][2]={" ","1","2","3","4","5","6","7","8","9","A","B","C"};
  319.  int which_gc;
  320.  
  321.  switch(grid_type)
  322.    {
  323.    case GAME_HEXAGON:
  324.     xpos=x*scalex+(y%2)*scalex/2;
  325.     ypos=y*scaley+scaley/3;
  326.     outline[0].x=xpos; outline[0].y=ypos;
  327.     break;
  328.    case GAME_SQUARE:
  329.     xpos=x*scalex;
  330.     ypos=y*scaley;
  331.     break;
  332.    case GAME_TRIANGLE:
  333.     xpos=x*scalex+scalex/2;
  334.     ypos=y*scaley*2-((x+y)%2)*scaley+scaley;
  335.     if((x+y)%2)
  336.        outline[4].x=xpos+scalex/2, outline[4].y=ypos+2*scaley;
  337.     else
  338.        outline[0].x=xpos+scalex/2, outline[0].y=ypos-scaley;
  339.     break;
  340.    }
  341.  
  342.  if(value&UNSEEN)
  343.    {
  344.     if(value&THINK_BOMB)
  345.        which_gc=GC_THINK_BACK;
  346.     else
  347.        which_gc=GC_UNSEEN;
  348.    }
  349.  else
  350.    {
  351.     if(value&ACTUAL_BOMB)
  352.        which_gc=GC_ACTUAL_BACK;
  353.     else
  354.        which_gc=GC_BLANK;
  355.    }
  356.  
  357.  switch(grid_type)
  358.    {
  359.    case GAME_HEXAGON:
  360.     XFillPolygon(display,play_window,gc[which_gc],outline,7,Convex,CoordModePrevious);
  361.     break;
  362.    case GAME_SQUARE:
  363.     XFillRectangle(display,play_window,gc[which_gc],xpos,ypos,scalex,scaley);
  364.     break;
  365.    case GAME_TRIANGLE:
  366.     if((x+y)%2)
  367.        XFillPolygon(display,play_window,gc[which_gc],&outline[4],4,Convex,CoordModePrevious);
  368.     else
  369.        XFillPolygon(display,play_window,gc[which_gc],&outline[0],4,Convex,CoordModePrevious);
  370.     break;
  371.    }
  372.  
  373.  if(value&UNSEEN)
  374.    {
  375.     if(value&THINK_BOMB)
  376.        XCopyArea(display,bombpix[1],play_window,gc[GC_THINK_BACK],0,0,pixw,pixh,xpos,ypos);
  377.    }
  378.  else
  379.    {
  380.     if(value&ACTUAL_BOMB)
  381.        XCopyArea(display,bombpix[0],play_window,gc[GC_ACTUAL_BACK],0,0,pixw,pixh,xpos,ypos);
  382.     else
  383.        if((value&~CORRECT)>0 && (value&~CORRECT)<=12)
  384.          {
  385.           int text_xpos=xpos+pixw/2-xoffset;
  386.           int text_ypos=ypos+pixh/2+yoffset;
  387.           XDrawString(display,play_window,gc[GC_NUMBERS],text_xpos,text_ypos,grid_numbers[(value&~CORRECT)],1);
  388.          }
  389.    }
  390.  
  391.  if(value&CORRECT)
  392.     which_gc=GC_CORRECT;
  393.  else
  394.     which_gc=GC_BOMB;
  395.  
  396.  switch(grid_type)
  397.    {
  398.    case GAME_HEXAGON:
  399.     XDrawLines(display,play_window,gc[which_gc],outline,7,CoordModePrevious);
  400.     break;
  401.    case GAME_SQUARE:
  402.     XDrawRectangle(display,play_window,gc[which_gc],xpos,ypos,scalex-1,scaley-1);
  403.     break;
  404.    case GAME_TRIANGLE:
  405.     if((x+y)%2)
  406.        XDrawLines(display,play_window,gc[which_gc],&outline[4],4,CoordModePrevious);
  407.     else
  408.        XDrawLines(display,play_window,gc[which_gc],&outline[0],4,CoordModePrevious);
  409.     break;
  410.    }
  411.  
  412. }
  413.  
  414.  
  415. /*++++++++++++++++++++++++++++++++++++++
  416.   A callback that is activated by an expose event on the play area window.
  417.  
  418.   Widget w The widget that caused the callback.
  419.  
  420.   XtPointer va Not used.
  421.  
  422.   XEvent* e The event that requires action.
  423.  
  424.   Boolean* vb Not used.
  425.  
  426.   This function is only ever called from the Xt Intrinsics routines.
  427.   ++++++++++++++++++++++++++++++++++++++*/
  428.  
  429. static void size_expose_proc(Widget w,XtPointer va,XEvent* e,Boolean* vb)
  430. {
  431.  if(e->type==ConfigureNotify)
  432.     ScaleWindow();
  433.  
  434.  if(e->type==MapNotify || (e->type==Expose && !e->xexpose.count))
  435.     DrawGrid();
  436. }
  437.  
  438.  
  439. /*++++++++++++++++++++++++++++++++++++++
  440.   Scales the window.
  441.   ++++++++++++++++++++++++++++++++++++++*/
  442.  
  443. void ScaleWindow(void)
  444. {
  445.  unsigned short width,height;
  446.  unsigned short old_width,old_height;
  447.  unsigned short new_width=0,new_height=0;
  448.  
  449.  XtVaGetValues(play_area,XtNwidth,&old_width,XtNheight,&old_height,NULL);
  450.  
  451.  new_width=old_width;
  452.  new_height=old_height;
  453.  
  454.  do{
  455.     width=new_width;
  456.     height=new_height;
  457.  
  458.     switch(grid_type)
  459.       {
  460.       case GAME_HEXAGON:
  461.        scalex=(int)width*2/(2*grid_width+1);
  462.        scaley=(int)height*4/(4*grid_height+1);
  463.        scalex=(int)(scalex<(scaley*8/7)?scalex:(scaley*8/7));
  464.        scaley=(scalex*7+8)/8;
  465.        new_width =scalex*(2*grid_width+1)/2;
  466.        new_height=scaley*(4*grid_height+1)/4;
  467.        break;
  468.       case GAME_SQUARE:
  469.        scalex=(int)width /grid_width;
  470.        scaley=(int)height/grid_height;
  471.        scalex=scaley=(int)(scalex<scaley?scalex:scaley);
  472.        new_width =scalex*grid_width;
  473.        new_height=scaley*grid_height;
  474.        break;
  475.       case GAME_TRIANGLE:
  476.        scalex=(int)width*2/(2*grid_width+1);
  477.        scaley=(int)height/(2*grid_height);
  478.        scalex=(int)(scalex<(scaley*8/7)?scalex:(scaley*8/7));
  479.        scaley=(scalex*7+8)/8;
  480.        new_width =scalex*grid_width+scalex;
  481.        new_height=2*scaley*grid_height;
  482.        break;
  483.       }
  484.    }
  485.  while(new_width!=width && new_height!=height);
  486.  
  487.  if(new_width!=old_width || new_height!=old_height)
  488.    {
  489.     new_width-=old_width;
  490.     new_height-=old_height;
  491.     XtVaGetValues(XtParent(XtParent(play_area)),XtNwidth,&width,XtNheight,&height,NULL);
  492.     XResizeWindow(display,XtWindow(XtParent(XtParent(play_area))),(unsigned)(width+new_width),(unsigned)(height+new_height));
  493.    }
  494.  else
  495.    {
  496.     int i;
  497.  
  498.     if(grid_type==GAME_HEXAGON)
  499.       {
  500.        /* outline[0] is filled at the time of drawing */
  501.        outline[1].x= (int)scalex/2-1;   outline[1].y=-(int)scaley  /3;
  502.        outline[2].x= (int)scalex/2;     outline[2].y= (int)scaley  /3;
  503.        outline[3].x= 0;                 outline[3].y= (int)scaley*2/3;
  504.        outline[4].x=-(int)scalex/2;     outline[4].y= (int)scaley  /3;
  505.        outline[5].x=-(int)scalex/2+1;   outline[5].y=-(int)scaley  /3;
  506.        outline[6].x= 0;                 outline[6].y=-(int)scaley*2/3;
  507.       }
  508.     else
  509.        if(grid_type==GAME_TRIANGLE)
  510.          {
  511.           /* outline[0] is filled at the time of drawing */
  512.           outline[1].x=-(int)scalex+1;    outline[1].y= (int)scaley*2-1;
  513.           outline[2].x= (int)scalex*2-2;  outline[2].y=0;
  514.           outline[3].x=-(int)scalex+1;    outline[3].y=-(int)scaley*2+1;
  515.           /* outline[4] is filled at the time of drawing */
  516.           outline[5].x=-(int)scalex+1;    outline[5].y=-(int)scaley*2;
  517.           outline[6].x= (int)scalex*2-2;  outline[6].y=0;
  518.           outline[7].x=-(int)scalex+1;    outline[7].y= (int)scaley*2;
  519.          }
  520.  
  521.     for(i=0;i<2;i++)
  522.       {
  523.        if(grid_type==GAME_HEXAGON)
  524.           pixw=scalex,pixh=scaley*2/3;
  525.        else
  526.           pixw=scalex,pixh=scaley;
  527.  
  528.        if(bombpix[i])
  529.           XFreePixmap(display,bombpix[i]);
  530.  
  531.        bombpix[i]=XCreatePixmap(display,XtWindow(play_area),pixw,pixh,(unsigned)DefaultDepthOfScreen(XtScreen(play_area)));
  532.  
  533.        XFillRectangle(display,bombpix[i],gc[i+1],0,0,pixw,pixh);
  534.  
  535.        if(i==0)
  536.          {
  537.           XFillArc(display,bombpix[i],gc[GC_BOMB],(signed)pixw/4,(signed)pixh/2-2,pixw/2,pixh/2,0,360*64);
  538.           XFillRectangle(display,bombpix[i],gc[GC_BOMB],3*(signed)pixw/8,3*(signed)pixh/8,pixw/4,pixh/4);
  539.           XDrawLine(display,bombpix[i],gc[GC_BOMB],(signed)pixw/2,(signed)pixh/2,(signed)pixw/2,(signed)pixh/4);
  540.           XDrawArc(display,bombpix[i],gc[GC_BOMB],(signed)pixw/2,2,pixw/2,pixh/2,70*64,110*64);
  541.          }
  542.        else
  543.          {
  544.           XPoint points[3];
  545.           XFillArc(display,bombpix[i],gc[GC_BOMB],(signed)pixw/4,(signed)pixh*3/4-2,pixw/2,pixh/2,0,180*64);
  546.           XDrawLine(display,bombpix[i],gc[GC_BOMB],(signed)pixw/2,(signed)pixh*3/4,(signed)pixw/2,(signed)pixh/4);
  547.           points[0].x=pixw/2;   points[0].y=pixh/8;
  548.           points[1].x=pixw*4/5; points[1].y=pixh/4;
  549.           points[2].x=pixw/2;   points[2].y=pixh*3/8;
  550.           XFillPolygon(display,bombpix[i],gc[GC_BOMB],points,3,Convex,CoordModeOrigin);
  551.          }
  552.       }
  553.  
  554.     XClearWindow(display,play_window);
  555.     DrawGrid();
  556.    }
  557. }
  558.  
  559. /*++++++++++++++++++++++++++++++++++++++
  560.   A callback that is activated by a mouse press in the play area window.
  561.  
  562.   Widget w The widget that caused the callback.
  563.  
  564.   XtPointer va Not used.
  565.  
  566.   XEvent* e The event that requires action.
  567.  
  568.   Boolean* vb Not used.
  569.  
  570.   This function is only ever called from the Xt Intrinsics routines.
  571.   ++++++++++++++++++++++++++++++++++++++*/
  572.  
  573. static void mouse_press_proc(Widget w,XtPointer va,XEvent* e,Boolean* vb)
  574. {
  575.  int x=-1,y=-1;
  576.  int x_guess,y_guess,dx,dy;
  577.  int i,j,d,dmin=1e6;
  578.  
  579.  switch(grid_type)
  580.    {
  581.    case GAME_HEXAGON:
  582.     y_guess=e->xbutton.y/scaley;
  583.     x_guess=(e->xbutton.x-(y_guess%2)*scalex/2)/scalex;
  584.     for(i=x_guess-1;i<=(x_guess+1);i++)
  585.        for(j=y_guess-1;j<=(y_guess+1);j++)
  586.          {
  587.           if(i<0 || i>=grid_width || j<0 || j>=grid_height)
  588.              continue;
  589.           dx=e->xbutton.x-(i*scalex+(1+(j%2))*scalex/2);
  590.           dy=e->xbutton.y-(j*scaley+2*scaley/3);
  591.           d=dx*dx+dy*dy;
  592.           if(d<dmin)
  593.             {x=i;y=j;dmin=d;}
  594.       }
  595.     break;
  596.    case GAME_SQUARE:
  597.     x=e->xbutton.x/scalex;
  598.     y=e->xbutton.y/scaley;
  599.     break;
  600.    case GAME_TRIANGLE:
  601.     x_guess=e->xbutton.x/scalex;
  602.     y=e->xbutton.y/(2*scaley);
  603.     for(i=x_guess-1;i<=(x_guess+1);i++)
  604.       {
  605.        if(i<0 || i>=grid_width)
  606.           continue;
  607.        dx=e->xbutton.x-(i*scalex+scalex);
  608.        dy=e->xbutton.y-(y*2*scaley+(1+(1+i+y)%2)*scaley*2/3);
  609.        d=dx*dx+dy*dy;
  610.        if(d<dmin)
  611.          {x=i;dmin=d;}
  612.       }
  613.     break;
  614.    }
  615.  
  616.  if(x<0 || x>=grid_width || y<0 || y>=grid_height)
  617.     {XBell(display,0);return;}
  618.  
  619.  switch(e->xbutton.button)
  620.    {
  621.    case 1: SelectSquare(x,y); break;
  622.    case 2: SelectAdjacent(x,y); break;
  623.    case 3: MarkBomb(x,y); break;
  624.    }
  625. }
  626.  
  627.  
  628. /*++++++++++++++++++++++++++++++++++++++
  629.   A callback that is activated by a key press in the play area window.
  630.  
  631.   Widget w The widget that caused the callback.
  632.  
  633.   XtPointer va Not used.
  634.  
  635.   XEvent* e The event that requires action.
  636.  
  637.   Boolean* vb Not used.
  638.  
  639.   This function is only ever called from the Xt Intrinsics routines.
  640.   ++++++++++++++++++++++++++++++++++++++*/
  641.  
  642. static void key_press_proc(Widget w,XtPointer va,XEvent* e,Boolean* vb)
  643. {
  644.  KeySym k=XLookupKeysym((XKeyEvent*)e,0);
  645.  Boolean shift=((XKeyEvent*)e)->state==ShiftMask || ((XKeyEvent*)e)->state==ControlMask;
  646.  
  647.  if(k==NoSymbol)return;
  648.  
  649.  switch(k)
  650.    {
  651.    case XK_1:
  652.     status=GAME_LEVEL;
  653.     break;
  654.    case XK_2:
  655.     status=GAME_LEVEL+1;
  656.     break;
  657.    case XK_3:
  658.     status=GAME_LEVEL+2;
  659.     break;
  660.  
  661.    case XK_s:
  662.     if(shift)
  663.        status=GAME_SQUARE;
  664.     else
  665.        status=GAME_START;
  666.     break;
  667.  
  668.    case XK_h:
  669.     if(shift)
  670.        status=GAME_HEXAGON;
  671.     else
  672.        PrintHighScores(-1);
  673.     break;
  674.  
  675.    case XK_q:
  676.     status=GAME_QUIT;
  677.     break;
  678.  
  679.    case XK_t:
  680.     if(shift)
  681.        status=GAME_TRIANGLE;
  682.     break;
  683.  
  684.    default:
  685.    }
  686.  
  687. }
  688.  
  689.  
  690. /*++++++++++++++++++++++++++++++++++++++
  691.   This function changes the state of the status flag.
  692.  
  693.   Widget widget Not used.
  694.  
  695.   XtPointer clientData The new status.
  696.  
  697.   XtPointer callData Not used.
  698.  
  699.   This function is only ever called from the Xt Intrinsics routines.
  700.   ++++++++++++++++++++++++++++++++++++++*/
  701.  
  702. static void change_status_proc(Widget widget,XtPointer clientData,XtPointer callData)
  703. {
  704.  status=(int)clientData;
  705. }
  706.  
  707. /*++++++++++++++++++++++++++++++++++++++
  708.   This function displays the hi-scores.
  709.  
  710.   Widget widget Not used.
  711.  
  712.   XtPointer clientData Not used.
  713.  
  714.   XtPointer callData Not used.
  715.  
  716.   This function is only ever called from the Xt Intrinsics routines.
  717.   ++++++++++++++++++++++++++++++++++++++*/
  718.  
  719. static void hiscore_proc(Widget widget,XtPointer clientData,XtPointer callData)
  720. {
  721.  PrintHighScores(-1);
  722. }
  723.  
  724.  
  725. /*++++++++++++++++++++++++++++++++++++++
  726.   Sets the number of UXB in the grid.
  727.  
  728.   int n The number of UXB.
  729.   ++++++++++++++++++++++++++++++++++++++*/
  730.  
  731. void SetUXB(int n)
  732. {
  733.  char string[16];
  734.  
  735.  sprintf(string,"UXB : %3d",n);
  736.  XtVaSetValues(uxb_w,XtNlabel,string,NULL);
  737. }
  738.  
  739.  
  740. /*------------ The clock -------------*/
  741.  
  742. static int ticks;
  743. static XtIntervalId id;
  744. static struct timeval starttimeval;
  745.  
  746. /*++++++++++++++++++++++++++++++++++++++
  747.   The function called for each clock tick.
  748.  
  749.   XtPointer p Not used.
  750.  
  751.   XtIntervalId i Not used.
  752.  
  753.   This function is only called from the Intrinsics.
  754.   ++++++++++++++++++++++++++++++++++++++*/
  755.  
  756. static void display_clock(XtPointer p,XtIntervalId i)
  757. {
  758.  char string[16];
  759.  int ticks1000=msecs();
  760.  
  761.  ticks=ticks1000/1000;
  762.  ticks1000-=1000*ticks;
  763.  
  764.  id=XtAppAddTimeOut(app_context,(unsigned)(1000-ticks1000),(XtTimerCallbackProc)display_clock,NULL);
  765.  
  766.  sprintf(string,"Time : %4d",ticks);
  767.  XtVaSetValues(clock_w,XtNlabel,string,NULL);
  768. }
  769.  
  770.  
  771. /*++++++++++++++++++++++++++++++++++++++
  772.   Starts the clock
  773.  
  774.   int reset If 0 then resets the clock else if 1 then starts the clock.
  775.   ++++++++++++++++++++++++++++++++++++++*/
  776.  
  777. void StartClock(int reset)
  778. {
  779.  if(reset)
  780.    {
  781.     gettimeofday(&starttimeval,NULL);
  782.     display_clock(NULL,0);
  783.    }
  784.  else
  785.    {
  786.     char string[16];
  787.     sprintf(string,"Time :    0");
  788.     XtVaSetValues(clock_w,XtNlabel,string,NULL);
  789.    }
  790. }
  791.  
  792.  
  793. /*++++++++++++++++++++++++++++++++++++++
  794.   Stops the clock and returns the time in seconds.
  795.  
  796.   int StopClock Returns the time in seconds.
  797.   ++++++++++++++++++++++++++++++++++++++*/
  798.  
  799. int StopClock(void)
  800. {
  801.  char string[16];
  802.  
  803.  XtRemoveTimeOut(id);
  804.  ticks=msecs();
  805.  
  806.  sprintf(string,"Time : %8.3f",(double)ticks/1000.0);
  807.  XtVaSetValues(clock_w,XtNlabel,string,NULL);
  808.  
  809.  return(ticks);
  810. }
  811.  
  812.  
  813. /*++++++++++++++++++++++++++++++++++++++
  814.   Returns the number of milliseconds since starting the game.
  815.  
  816.   int msecs The number of milli-seconds.
  817.   ++++++++++++++++++++++++++++++++++++++*/
  818.  
  819. static int msecs(void)
  820. {
  821.  struct timeval nowtimeval;
  822.  
  823.  gettimeofday(&nowtimeval,NULL);
  824.  
  825.  return(1000*(nowtimeval.tv_sec-starttimeval.tv_sec)+(nowtimeval.tv_usec-starttimeval.tv_usec)/1000);
  826. }
  827.